package sdk.webview.fmc.com.fmcsdk.util;

import android.util.Base64;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.MessageDigest;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

public class DESCoder {
	private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
            .toCharArray();
	private static final int[] IA = new int[256];
    static {
        Arrays.fill(IA, -1);
        for (int i = 0, iS = CA.length; i < iS; i++)
            IA[CA[i]] = i;
        IA['='] = 0;
    }
	public static final String ALGORITHM = "DES";
	public static final String KEY_MD5 = "MD5";
	public static final String KEY = "SZSSSZJKJYXGS";

	/**
	 * 转换密钥<br>
	 * 
	 * @param key
	 * @return
	 * @throws Exception
	 */
	private static Key toKey(byte[] key) throws Exception {
		DESKeySpec dks = new DESKeySpec(key);
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
		SecretKey secretKey = keyFactory.generateSecret(dks);

		// 当使用其他对称加密算法时，如AES、Blowfish等算法时，用下述代码替换上述三行代码
		// SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);

		return secretKey;
	}
	
	public final static byte[] encodeToBase64(String sStr) {
		 int sLen = sStr != null ? sStr.length() : 0;
        if (sLen == 0)
            return new byte[0];
        byte[] sArr = new byte[0];
        try{
        	sArr = sStr.getBytes("UTF-8");
        	return encodeToBase64(sArr);
        }catch(UnsupportedEncodingException e){
        	return new byte[0];
        }  
	}
	
	/**
	 * Base64编码
	 * @param sStr
	 * @param lineSep
	 * @return
	 */
	public final static byte[] encodeToBase64(byte[] sArr) {
		boolean lineSep = false;
        // Check special case
        int sLen = sArr != null ? sArr.length : 0;
        if (sLen == 0)
            return new byte[0];

        int eLen = (sLen / 3) * 3; // Length of even 24-bits.
        int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
        int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of
                                                                // returned
                                                                // array
        byte[] dArr = new byte[dLen];

        // Encode even 24-bits
        for (int s = 0, d = 0, cc = 0; s < eLen;) {
            // Copy next three bytes into lower 24 bits of int, paying attension
            // to sign.
            int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8
                    | (sArr[s++] & 0xff);

            // Encode the int into four chars
            dArr[d++] = (byte) CA[(i >>> 18) & 0x3f];
            dArr[d++] = (byte) CA[(i >>> 12) & 0x3f];
            dArr[d++] = (byte) CA[(i >>> 6) & 0x3f];
            dArr[d++] = (byte) CA[i & 0x3f];

            // Add optional line separator
            if (lineSep && ++cc == 19 && d < dLen - 2) {
                dArr[d++] = '\r';
                dArr[d++] = '\n';
                cc = 0;
            }
        }

        // Pad and encode last bits if source isn't an even 24 bits.
        int left = sLen - eLen; // 0 - 2.
        if (left > 0) {
            // Prepare the int
            int i = ((sArr[eLen] & 0xff) << 10)
                    | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);

            // Set last four chars
            dArr[dLen - 4] = (byte) CA[i >> 12];
            dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f];
            dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '=';
            dArr[dLen - 1] = '=';
        }
        return dArr;
    }
	
	public final static byte[] decodeFromBase64(String str, boolean used) {
        // Check special case
        int sLen = str != null ? str.length() : 0;
        if (sLen == 0)
            return new byte[0];

        // Count illegal characters (including '\r', '\n') to know what size the
        // returned array will be,
        // so we don't have to reallocate & copy it later.
        int sepCnt = 0; // Number of separator characters. (Actually illegal
                        // characters, but that's a bonus)
        for (int i = 0; i < sLen; i++)
            // If input is "pure" (I.e. no line separators or illegal chars)
            // base64 this loop can be commented out.
            if (IA[str.charAt(i)] < 0)
                sepCnt++;

        // Check so that legal chars (including '=') are evenly divideable by 4
        // as specified in RFC 2045.
        if ((sLen - sepCnt) % 4 != 0)
            return null;

        // Count '=' at end
        int pad = 0;
        for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0;)
            if (str.charAt(i) == '=')
                pad++;

        int len = ((sLen - sepCnt) * 6 >> 3) - pad;

        byte[] dArr = new byte[len]; // Preallocate byte[] of exact length

        for (int s = 0, d = 0; d < len;) {
            // Assemble three bytes into an int from four "valid" characters.
            int i = 0;
            for (int j = 0; j < 4; j++) { // j only increased if a valid char
                                            // was found.
                int c = IA[str.charAt(s++)];
                if (c >= 0)
                    i |= c << (18 - j * 6);
                else
                    j--;
            }
            // Add the bytes
            dArr[d++] = (byte) (i >> 16);
            if (d < len) {
                dArr[d++] = (byte) (i >> 8);
                if (d < len)
                    dArr[d++] = (byte) i;
            }
        }
        return dArr;
    }

	/**
	 * 解密
	 * 
	 * @param data
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] data, String key) throws Exception {
		Key k = toKey(encodeToBase64(key));

		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, k);

		return cipher.doFinal(data);
	}

	/**
	 * 加密
	 * 
	 * @param data
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data, String key)throws Exception {
		Key k = toKey(encodeToBase64(key));
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, k);

		return cipher.doFinal(data);
	}
	
	/** 
	 * MD5摘要 
	 *  
	 * @param data 
	 * @return 
	 * @throws Exception
	 */  
	public static byte[] encryptMD5(byte[] data) throws Exception {
	  
	    MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
	    md5.update(data);  
	  
	    return md5.digest();  
	  
	}  
	
	
    public static void main(String[] args) throws Exception {
        String inputStr = "123456";
        System.err.println("原文:\t" + inputStr);
  
        System.err.println("密钥:\t" + KEY);
  
        byte[] inputData = inputStr.getBytes();  
        inputData = DESCoder.encrypt(inputData, KEY);  
  
        System.err.println("加密后:\t" + new String(DESCoder.encodeToBase64(inputData)));
        
        System.err.println("加密后2:\t" + new String(DESCoder.encodeToBase64(inputStr)));
  
        byte[] outputData = DESCoder.decrypt(inputData, KEY);  
        String outputStr = new String(outputData);
  
        System.err.println("解密后:\t" + outputStr);
        
        System.err.println("解密后2:\t" + new String(DESCoder.decodeFromBase64(new String(DESCoder.encodeToBase64(inputStr)), false)));
  
        System.err.println("摘要:\t" + new String(DESCoder.encodeToBase64(encryptMD5(inputData))));
        //System.err.println("摘要后加密:\t" + new String(DESCoder.encodeToByte(DESCoder.encrypt(DESCoder.encodeToByte(md), KEY))));
    }

    /**
     * 文件转base64字符串
     * @param file
     * @return
     */
    public static String fileToBase64(File file) {
        String base64 = null;
        InputStream in = null;
        try {
            in = new FileInputStream(file);
            byte[] bytes = new byte[in.available()];
            int length = in.read(bytes);
            base64 = Base64.encodeToString(bytes, 0, length, Base64.DEFAULT);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return base64;
    }


}